﻿using DevExpress.Data;
using DevExpress.Data.Filtering;
using DevExpress.Data.Linq;
using DevExpress.Data.Linq.Helpers;
using System.Linq.Dynamic.Core;
using System.Linq.Expressions;
using System.Text.Json.Nodes;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Domain.Services;
using Volo.Abp.Uow;
using YAKEJI.Abp.Domain.Repositories;
using YAPACS.BusinessObjects.Exams;
using YAPACS.BusinessObjects.Managements.Devices;
using YAPACS.Organizations;
using YAPACS.RisServer.Abstractions;
using YAPACS.RisServer.Services.Dtos;
using YAPACS.RisServer.Workflows.Match;
using YAPACS.Workflows;

namespace YAPACS.RisServer.Services;

public class MatchService(IGetStudyAdvancedSearchView getStudyAdvancedSearchView,
    IGetExamAdvancedSearchView getExamAdvancedSearchView,
    IExamConvertExpression examConvertExpression,
    IStudyConvertExpression studyConvertExpression,
    IRepository<Exam, Guid> examRepository,
    IRepository<Study, Guid> studyRepository,
    IUnitOfWorkManager unitOfWorkManager,
    IRepository<Department, Guid> departmentRepository,
    ICurrentUserOrganization currentUserOrganization,
    IGetHeaders getHeaders,
    IRepository<Report, Guid> reportRepository,
    IRepository<ApplicationUser, Guid> userRepository,
    IRepository<Institution, Guid> institutionRepository,
    IRepository<DepartmentDeviceType> departmentDeviceTypeRepository) : DomainService, IMatchService, ITransientDependency
{
    private readonly IUnitOfWorkManager _unitOfWorkManager = unitOfWorkManager;
    private readonly IGetStudyAdvancedSearchView _getStudyAdvancedSearchView = getStudyAdvancedSearchView;
    private readonly IGetExamAdvancedSearchView _getExamAdvancedSearchView = getExamAdvancedSearchView;
    private readonly IExamConvertExpression _examConvertExpression = examConvertExpression;
    private readonly IStudyConvertExpression _studyConvertExpression = studyConvertExpression;
    private readonly IRepository<Exam, Guid> _examRepository = examRepository;
    private readonly IRepository<Study, Guid> _studyRepository = studyRepository;
    private readonly IRepository<Department, Guid> _departmentRepository = departmentRepository;
    private readonly IRepository<Report, Guid> _reportRepository = reportRepository;
    private readonly ICurrentUserOrganization _currentUserOrganization = currentUserOrganization;
    private readonly IRepository<ApplicationUser, Guid> _userRepository = userRepository;
    private readonly IRepository<Institution, Guid> _institutionRepository = institutionRepository;
    private readonly IRepository<DepartmentDeviceType> _departmentDeviceTypeRepository = departmentDeviceTypeRepository;
    private readonly IGetHeaders _getHeaders = getHeaders;

    public async Task<WorkflowOutput> GetExamAdvancedSearchViewAsync()
    {
        try
        {
            var workflowOutput = await _getExamAdvancedSearchView.InvokeAsync([]);
            return workflowOutput;
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await _unitOfWorkManager.Current.RollbackAsync();
            return new WorkflowOutput
            {
                Success = false,
                Error = ex.Message
            };
        }

    }
    public async Task<WorkflowOutput> GetStudyAdvancedSearchViewAsync()
    {
        try
        {
            var workflowOutput = await _getStudyAdvancedSearchView.InvokeAsync([]);
            return workflowOutput;
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await _unitOfWorkManager.Current.RollbackAsync();
            return new WorkflowOutput
            {
                Success = false,
                Error = ex.Message
            };
        }
    }
    public async Task<WorkflowOutput> GetExamsAsync(DataGridRequest request)
    {
        try
        {
            WorkflowOutput workflowOutput = new() { Success = true };
            bool precision = false;
            var columnsOutput = await _getHeaders.InvokeAsync([]);
            if (!columnsOutput.Success)
            {
                throw new Exception(columnsOutput.Error);
            }
            string columnsString = ExtendColumnItem(columnsOutput.Data as string);

            var columns = columnsString.Deserialize<Column[]>();
            //根据获取到的表头查询列表
            var selectStr = columns.GetColumnString();
            var department = await _departmentRepository.GetAsync(_currentUserOrganization.DepartmentId.Value);
            var query = await _examRepository.GetQueryableAsync();
            if (request.UserData != null && request.UserData.Count > 0)
            {
                const string key = "Output";
                var input = new WorkflowInput { { "Input", request.UserData } };
                workflowOutput = await _examConvertExpression.InvokeAsync(input);
                if (!workflowOutput.Success)
                {
                    return workflowOutput;
                }
                if (input.ContainsKey(key) && input.GetValueOrDefault(key) is Expression<Func<Exam, bool>> expression)
                {
                    query = query.Where(expression);
                }
                if (input.ContainsKey("Precision"))
                {
                    precision = true;
                }
            }
            else
            {
                var startTime = DateTime.Today;
                var endTime = DateTime.Today.AddDays(1).Date;
                query = query.Where(e => e.ExamTime >= startTime && e.ExamTime < endTime);
            }
            if (!precision)
            {
                query = query.Where(e => e.Studies.Count == 0);
            }
            //查询数据
            query = query.Where(e => e.Department == department);
            if (request.Sort != null && request.Sort.Count > 0)
            {
                foreach (var sort in request.Sort)
                {
                    var column = columns.Where(e => e.DataField == sort.Selector).FirstOrDefault();
                    if (column != null)
                    {
                        if (!string.IsNullOrWhiteSpace(column.Order))
                        {
                            sort.Selector = column.Order;
                        }
                        else if (!string.IsNullOrWhiteSpace(column.Property))
                        {
                            sort.Selector = column.Property;
                        }
                    }
                }
            }
            else
            {
                request.Sort = new List<DataGridRequest.SortModel>() { new() { Selector = "Oid", Desc = true } };
            }
            var orders = request.Sort.Select(e => new ServerModeOrderDescriptor(new OperandProperty(e.Selector), e.Desc));
            var orderQuery = query.MakeOrderBy(new CriteriaToExpressionConverter(), orders);
            var skipQuery = CriteriaToQueryableExtender.Skip(orderQuery, request.Skip);
            var list = CriteriaToQueryableExtender.Take(skipQuery, request.Take).Select(selectStr).ToDynamicList();
            var totalCount = await AsyncExecuter.CountAsync(query);
            workflowOutput.Data = new DataGridDto()
            {
                Columns = columnsOutput.Data,
                Rows = list,
                TotalCount = totalCount
            };
            return workflowOutput;
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await _unitOfWorkManager.Current.RollbackAsync();
            return new WorkflowOutput
            {
                Success = false,
                Error = ex.Message
            };
        }
    }
    public async Task<WorkflowOutput> GetReportExamsAsync(DataGridRequest request)
    {
        try
        {
            WorkflowOutput workflowOutput = new() { Success = true };
            bool precision = false;
            var columnsOutput = await _getHeaders.InvokeAsync([]);
            if (!columnsOutput.Success)
            {
                throw new Exception(columnsOutput.Error);
            }
            string columnsString = ExtendColumnItem(columnsOutput.Data as string);

            var columns = columnsString.Deserialize<Column[]>();
            //根据获取到的表头查询列表
            var selectStr = columns.GetColumnString();
            var department = await _departmentRepository.GetAsync(_currentUserOrganization.DepartmentId.Value);
            var query = await _examRepository.GetQueryableAsync();
            if (request.UserData != null && request.UserData.Count > 0)
            {
                request.UserData["isReport"] = true;
                const string key = "Output";
                var input = new WorkflowInput { { "Input", request.UserData } };
                workflowOutput = await _examConvertExpression.InvokeAsync(input);
                if (!workflowOutput.Success)
                {
                    return workflowOutput;
                }
                if (input.ContainsKey(key) && input.GetValueOrDefault(key) is Expression<Func<Exam, bool>> expression)
                {
                    query = query.Where(expression);
                }
                if (input.ContainsKey("Precision"))
                {
                    precision = true;
                }
            }
            else
            {
                var startTime = DateTime.Today;
                var endTime = DateTime.Today.AddDays(1).Date;
                query = query.Where(e => e.RegisterTime >= startTime && e.RegisterTime < endTime);
            }
            if (!precision)
            {
                query = query.Where(e => e.Studies.Count == 0);
            }
            //查询数据
            query = query.Where(e => e.Department == department);
            if (request.Sort != null && request.Sort.Count > 0)
            {
                foreach (var sort in request.Sort)
                {
                    var column = columns.Where(e => e.DataField == sort.Selector).FirstOrDefault();
                    if (column != null)
                    {
                        if (!string.IsNullOrWhiteSpace(column.Order))
                        {
                            sort.Selector = column.Order;
                        }
                        else if (!string.IsNullOrWhiteSpace(column.Property))
                        {
                            sort.Selector = column.Property;
                        }
                    }
                }
            }
            else
            {
                request.Sort = new List<DataGridRequest.SortModel>() { new() { Selector = "Oid", Desc = true } };
            }
            var orders = request.Sort.Select(e => new ServerModeOrderDescriptor(new OperandProperty(e.Selector), e.Desc));
            var orderQuery = query.MakeOrderBy(new CriteriaToExpressionConverter(), orders);
            var skipQuery = CriteriaToQueryableExtender.Skip(orderQuery, request.Skip);
            var list = CriteriaToQueryableExtender.Take(skipQuery, request.Take).Select(selectStr).ToDynamicList();
            var totalCount = await AsyncExecuter.CountAsync(query);
            workflowOutput.Data = new DataGridDto()
            {
                Columns = columnsOutput.Data,
                Rows = list,
                TotalCount = totalCount
            };
            return workflowOutput;
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await _unitOfWorkManager.Current.RollbackAsync();
            return new WorkflowOutput
            {
                Success = false,
                Error = ex.Message
            };
        }
    }

    public async Task<WorkflowOutput> GetStudiesAsync(DataGridRequest request)
    {
        try
        {
            WorkflowOutput workflowOutput = new WorkflowOutput { Success = true };
            //查询数据
            var query = await _studyRepository.GetQueryableAsync();
            bool precision = false;
            if (request.UserData != null && request.UserData.Count > 0)
            {
                const string key = "Output";
                var input = new WorkflowInput { { "Input", request.UserData } };
                workflowOutput = await _studyConvertExpression.InvokeAsync(input);
                if (!workflowOutput.Success)
                {
                    return workflowOutput;
                }
                if (input.ContainsKey(key) && input.GetValueOrDefault(key) is Expression<Func<Study, bool>> expression)
                {
                    query = query.Where(expression);
                }
                if (input.ContainsKey("Precision"))
                {
                    precision = true;
                }
            }
            else
            {
                var startTime = DateTime.Today;
                var endTime = DateTime.Today.AddDays(1).Date;
                query = query.Where(e => (e.StudyDateTime >= startTime && e.StudyDateTime < endTime) || (e.CreationTime >= startTime && e.CreationTime < endTime));
            }
            if (!precision)
            {
                query = query.Where(e => e.Exams.Count == 0);
            }
            var department = await _departmentRepository.GetAsync(_currentUserOrganization.DepartmentId.Value);
            query = query.Where(e => e.Device.Station.Room.Department == department);
            if (request.Sort == null)
            {
                query = query.OrderByDescending(e => e.StudyDateTime);
            }
            else
            {
                var sort = request.Sort[0];
                query = sort.Selector switch
                {
                    "accessionNumber" => sort.Desc ? query.OrderByDescending(e => e.AccessionNumber) : query.OrderBy(e => e.AccessionNumber),
                    "patientName" => sort.Desc ? query.OrderByDescending(e => e.PatientName) : query.OrderBy(e => e.PatientName),
                    "patientSex" => sort.Desc ? query.OrderByDescending(e => e.PatientSex) : query.OrderBy(e => e.PatientSex),
                    "patientAge" => sort.Desc ? query.OrderByDescending(e => e.PatientAge) : query.OrderBy(e => e.PatientAge),
                    "studyId" => sort.Desc ? query.OrderByDescending(e => e.StudyId) : query.OrderBy(e => e.StudyId),
                    "deviceName" => sort.Desc ? query.OrderByDescending(e => e.Device.Name) : query.OrderBy(e => e.Device.Name),
                    "studyDateTime" => sort.Desc ? query.OrderByDescending(e => e.StudyDateTime) : query.OrderBy(e => e.StudyDateTime),
                    "manufacturer" => sort.Desc ? query.OrderByDescending(e => e.Manufacturer) : query.OrderBy(e => e.Manufacturer),
                    "manufacturerModelName" => sort.Desc ? query.OrderByDescending(e => e.ManufacturerModelName) : query.OrderBy(e => e.ManufacturerModelName),
                    _ => query.OrderByDescending(e => e.StudyDateTime)
                };
            }
            var data = await AsyncExecuter.ToListAsync(query.Skip(request.Skip).Take(request.Take).Select(e => new
            {
                e.Oid,
                e.StudyKey,
                e.PatientId,
                e.PatientName,
                e.PatientSex,
                e.StudyId,
                DeviceName = e.Device != null ? e.Device.Name : null,
                e.AccessionNumber,
                e.StudyDateTime,
                e.Manufacturer,
                e.ManufacturerModelName,
                e.PatientAge
            }));
            var totalCount = await AsyncExecuter.CountAsync(query);
            workflowOutput.Data = new DataGridDto()
            {
                Rows = data,
                TotalCount = totalCount
            };
            return workflowOutput;
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await _unitOfWorkManager.Current.RollbackAsync();
            return new WorkflowOutput
            {
                Success = false,
                Error = ex.Message
            };
        }
    }
    public async Task<WorkflowOutput> MatchAsync(IList<Guid> studyIds, Guid examId)
    {
        try
        {
            var exam = await _examRepository.GetAsync(examId);
            var studies = await _studyRepository.GetListAsync(e => studyIds.Contains(e.Oid));
            exam.Studies.AddIfNotContains(studies);
            return new WorkflowOutput
            {
                Success = true
            };
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await _unitOfWorkManager.Current.RollbackAsync();
            return new WorkflowOutput
            {
                Success = false,
                Error = ex.Message
            };
        }
    }
    public async Task<WorkflowOutput> MatchReportAsync(IList<Guid> studyIds, Guid examId)
    {
        try
        {
            var exam = await _examRepository.GetAsync(examId);
            var studies = await _studyRepository.GetListAsync(e => studyIds.Contains(e.Oid));
            exam.Studies.AddIfNotContains(studies);
            if (exam.Report == null)
            {
                var user = await _userRepository.GetAsync(_currentUserOrganization.UserId);
                var report = await _reportRepository.NewEntityAsync();
                report.ExamResult = ExamResult.Negative;
                report.ImageSeeing = "无";
                report.ImageDiagnosis = "无";
                report.ReportStatus = ReportStatus.Completed;
                //报告医生
                report.ReportDoctor = user;
                //报告机构
                //用户执业机构
                report.ReportInstitution = report.ReportDoctor.Institution;
                if (report.ReportInstitution == null)
                {
                    if (_currentUserOrganization.InstitutionId.HasValue)
                    {
                        //登录用户选择的医疗机构
                        report.ReportInstitution = await _institutionRepository.GetAsync(_currentUserOrganization.InstitutionId.Value);
                    }
                }
                if (report.ReportInstitution == null)
                {
                    //检查设备对应的医疗机构
                    var departmentDeviceType = await _departmentDeviceTypeRepository.FindAsync(e => e.DeviceType == exam.DeviceType);
                    report.ReportInstitution = departmentDeviceType.Department.Institution;
                }
                //报告开始时间
                report.ReportStartTime = Clock.Now;
                report.ReportTime = Clock.Now;
                report.AuditStartTime = Clock.Now;
                report.AuditTime = Clock.Now;
                report.AuditDoctor = user;
                //审核机构
                //用户执业机构
                report.AuditInstitution = report.AuditDoctor.Institution;
                if (report.AuditInstitution == null)
                {
                    if (_currentUserOrganization.InstitutionId.HasValue)
                    {
                        //登录用户选择的医疗机构
                        report.AuditInstitution = await _institutionRepository.GetAsync(_currentUserOrganization.InstitutionId.Value);
                    }
                }
                if (report.AuditInstitution == null)
                {
                    //检查设备对应的医疗机构
                    var departmentDeviceType = await _departmentDeviceTypeRepository.FindAsync(e => e.DeviceType == report.Exam.DeviceType);
                    report.AuditInstitution = departmentDeviceType.Department.Institution;
                }
                exam.Report = report;
                exam.ExamStatus= ExamStatus.Completed;
            }
            if (exam.ExamQueuing != null)
            { 
            exam.ExamQueuing.Status= ExamQueuingStatus.Completed;
            }
            return new WorkflowOutput
            {
                Success = true
            };
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
            await _unitOfWorkManager.Current.RollbackAsync();
            return new WorkflowOutput
            {
                Success = false,
                Error = ex.Message
            };
        }
    }

    private string ExtendColumnItem(string columnString)
    {
        var jsonArray = JsonNode.Parse(columnString).AsArray();
        if (!jsonArray.Where(x => x["dataField"] != null && x["dataField"].ToString().EqualsIgnoreCase("oid")).Any())
        {
            jsonArray.AddIfNotContains(new JsonObject
            {
                ["dataField"] = "oid",
                ["visible"] = false
            });
        }
        return jsonArray.ToString();
    }
}
